package com.itcoon.transform.assemble.handler.parameterized;

import com.itcoon.transform.assemble.handler.AssembleHandlerComposite;
import com.itcoon.transform.base.definition.InjectDefinition;
import com.itcoon.transform.base.exception.AssembleException;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

public class TargetCollectionHandler implements AssembleForTargetParameterizedTypeHandler {

    @Autowired
    private AssembleHandlerComposite composite;

    @Override
    public boolean support(ParameterizedType targetPropertyType, Object originGetterValue, List<InjectDefinition.InjectInfo> injectInfos) {
        return Collection.class.isAssignableFrom((Class<?>) targetPropertyType.getRawType());
    }

    @Override
    public Object handle(ParameterizedType targetPropertyType, Object originGetterValue, List<InjectDefinition.InjectInfo> injectInfos) {
        Type[] actualTypeArguments = targetPropertyType.getActualTypeArguments();
        Collection<?> sourceReturnValues = (Collection<?>) originGetterValue;
        Collection<Object> targetValues = emptyCollection(targetPropertyType);
        for (Object returnValue : sourceReturnValues) {
            if (returnValue != null) {
                Object proxy = composite.handle(actualTypeArguments[0], returnValue, injectInfos);
                Collections.addAll(targetValues, proxy);
            }
        }
        return targetValues;
    }

    public static <R> Collection<R> emptyCollection(ParameterizedType type) {
        Collection<Object> collection;
        if (Set.class.isAssignableFrom((Class) type.getRawType())) {
            collection = new HashSet<>();
        } else if (List.class.isAssignableFrom((Class) type.getRawType())) {
            collection = new ArrayList<>();
        } else {
            throw new AssembleException("Not supported collection wrapper.");
        }
        return (Collection<R>) collection;
    }
}
